
#include <vector>
#include "../aprtools/APRFile.h"
#include "../crypt/RSAKeyPairGenerator.h"
#include "../crypt/DSAKeyPairGenerator.h"
#include "../crypt/ECDSAKeyPairGenerator.h"
#include "../crypt/AESSymmetricKey.h"
#include "../utils/StringUtils.h"
#include "KeyDB.h"

/** Constructs the key database interface, opens the key database and
 * creates four KeyTableView classes, populated by EncryptionKey data,
 * DecryptionKey data, SigningKey data and CheckingKey data.
 *
 * This opens or creates a database of keys. The filename should not
 * have any extension. If the .db is not found, the .sql will be used
 * to populate the database. If the .sql also does not exist, a new
 * database will be created.
 * 
 * This also looks for the keys of main actors in the database, and
 * creates new key pairs if they are not present.
 * 
 * @param filename The name of the files containing the database. As
 * this refers to both .sql and .db files, this should not have a file
 * type extension.
 * 
 * @param WIPpwd The work-in-progress password for keys that are in
 * use. The work-in-progress password is a memory resident password
 * that prevents keys that need to be readily available in memory from
 * being written to disk unencrypted when the program shuts down. Keys
 * in the key databases that need to be secret are encrypted using
 * this password, which must be resupplied in the event that the
 * program is restarted.
 * 
 * @param iownname The main actor is identified by this name, which
 * allows this key to be treated specially as this main key is needed
 * to authenticate the program.
 * 
 * @param ownpwd The main actor has this as the password needed to
 * load its own key.
 * 
 * @param persists A boolean flag that sets whether to save the
 * database to disk. */
KeyDB::KeyDB(const char *filename, const char *WIPpwd, const char *iownname, const char *ownpwd, int persists) : SQLiteDB(filename, persists)
{
   ownname = (iownname) ? strdup(iownname) : NULL;
   keytablenames = getTableNamesFromCreateTablesIfNecessary();
   encryptionkeys = new KeyTableView(this, Key::KEYPURPOSE_ENCRYPTION,
      Key::keypurposetypename[0], WIPpwd, ownname, ownpwd);
   decryptionkeys = new KeyTableView(this, Key::KEYPURPOSE_DECRYPTION, 
      Key::keypurposetypename[1], WIPpwd, ownname, ownpwd);
   signingkeys = new KeyTableView(this, Key::KEYPURPOSE_SIGNING, 
      Key::keypurposetypename[2], WIPpwd, ownname, ownpwd);
   checkingkeys = new KeyTableView(this, Key::KEYPURPOSE_CHECKING, 
      Key::keypurposetypename[3], WIPpwd, ownname, ownpwd);
   oWIPpwd = (WIPpwd) ? strdup(WIPpwd) : NULL;
   if ((encryptionkeys->isGeneratingNewOwnKeysAcceptable()) &&
       (decryptionkeys->isGeneratingNewOwnKeysAcceptable()))
   {
      EncryptionKey *enckey = NULL;
      DecryptionKey *deckey = NULL;
      int retval = generateNewEncryptionDecryptionKeys(KEY_GENERATE_TYPE_ROOT_ENCRYPT_DECRYPT, ownname, &enckey, &deckey);
      // Insert these keys into the tables next!
      if (retval == 0)
      {
         Key t_enckey(this, *enckey, NULL);
         t_enckey.addKeyMark(KEYMARK_CHAINROOT, 1);
         t_enckey.setOwner(ownname);
         t_enckey.setDateCreatedToNow();
         t_enckey.commit();
         Key t_deckey(this, *deckey, ownpwd);
         t_deckey.addKeyMark(KEYMARK_CHAINROOT, 1);
         t_deckey.setOwner(ownname);
         t_deckey.setDateCreatedToNow();
         t_deckey.commit();
         encryptionkeys->retryGettingOwnKeys(ownpwd);
         decryptionkeys->retryGettingOwnKeys(ownpwd);
      } else
      {
         errprint("failed to generate new encryption/decryption keys for self '%s'", ownname);
      }
   }
   if ((signingkeys->isGeneratingNewOwnKeysAcceptable()) &&
       (checkingkeys->isGeneratingNewOwnKeysAcceptable()))
   {
      int retval = 0;
      SigningKey *sgnkey = NULL;
      CheckingKey *chkkey = NULL;
      retval = generateNewSigningCheckingKeys(KEY_GENERATE_TYPE_ROOT_CHECKING_SIGNING, ownname, &sgnkey, &chkkey);
      // Insert these keys into the tables next!
      if (retval == 0)
      {
         Key t_sgnkey(this, *sgnkey, ownpwd);
         t_sgnkey.addKeyMark(KEYMARK_CHAINROOT, 1);
         t_sgnkey.setOwner(ownname);
         t_sgnkey.setDateCreatedToNow();
         t_sgnkey.commit();
         Key t_chkkey(this, *chkkey, NULL);
         t_chkkey.addKeyMark(KEYMARK_CHAINROOT, 1);
         t_chkkey.setOwner(ownname);
         t_chkkey.setDateCreatedToNow();
         t_chkkey.commit();
         signingkeys->retryGettingOwnKeys(ownpwd);
         checkingkeys->retryGettingOwnKeys(ownpwd);
      } else
      {
         errprint("failed to generate new signing/checking keys for self '%s'", ownname);
      }
      SigningKey *sshsgnkey = NULL;
      CheckingKey *sshchkkey = NULL;
      char *ssh_owner = StringUtils::varprintf("%s_ssh", ownname);
      retval = generateNewSigningCheckingKeys(KEY_GENERATE_TYPE_ROOT_SSH_CHECKING_SIGNING, ssh_owner, &sshsgnkey, &sshchkkey);
      // Insert these keys into the tables next!
      if (retval == 0)
      {
         Key t_sshsgnkey(this, *sshsgnkey, NULL);
         t_sshsgnkey.addKeyMark(KEYMARK_CHAINROOT, 1);
         t_sshsgnkey.setOwner(ssh_owner);
         t_sshsgnkey.setDateCreatedToNow();
         t_sshsgnkey.commit();
         Key t_sshchkkey(this, *sshchkkey, NULL);
         t_sshchkkey.addKeyMark(KEYMARK_CHAINROOT, 1);
         t_sshchkkey.setOwner(ssh_owner);
         t_sshchkkey.setDateCreatedToNow();
         t_sshchkkey.commit();
      } else
      {
         errprint("failed to generate new SSH signing/checking keys for self '%s'", ownname);
      }
      free(ssh_owner);
   }
}

/** Destroys the key database views and interface. */
KeyDB::~KeyDB()
{
   if (encryptionkeys) delete encryptionkeys;
   encryptionkeys = NULL;
   if (decryptionkeys) delete decryptionkeys;
   decryptionkeys = NULL;
   if (signingkeys) delete signingkeys;
   signingkeys = NULL;
   if (checkingkeys) delete checkingkeys;
   checkingkeys = NULL;
   // doesn't need any destroy string list because all the string are const
   if (keytablenames) delete keytablenames;
   keytablenames = NULL;
   if (oWIPpwd) StringUtils::razeString(&oWIPpwd);
   if (ownname) free(ownname);
   ownname = NULL;
}

/** Generate a key pair for encryption and decryption into the
 * database with a given name.
 * 
 * @param ischained A boolean flag that states whether these keys are
 * to be inserted as part of a key chain. A key chain is a set of keys
 * owned by an actor, which begins with a root key. Keys are added
 * through time and removed when their reference count reaches zero.
 * 
 * @param isexpendable A boolean flag that states whether these keys
 * are expendable. If so, the key will be slowly moved into
 * obsolescence.
 * 
 * @param name The name for the key.
 * 
 * @param owner The actor that will own the key. Having this key to
 * encrypt or sign data proves that the actor in question is
 * legitimately working on behalf of the key owner. NULL signifies
 * that the name of the owner is the same as the name of the key.
 * 
 * @param policyoverridekeypair Allows the specification of a keypair
 * type that is not specified in the key generation policy.
 *
 * @return Returns zero when the keys were successfully generated and
 * added to their respective tables. This will return non-zero on an
 * error. */
int KeyDB::generateEncDecPairIntoDB(int ischained, int isexpendable,
   const char *name, const char *owner, AbstractKey::keypairtype policyoverridekeypair)
{
   // Chained means limited expendability
   int numberofancestors = encryptionkeys->countKeyChainOfOwner(owner) +
                           decryptionkeys->countKeyChainOfOwner(owner);
   int ischainroot = (numberofancestors == 0) && ischained;
   EncryptionKey *enckey = NULL;
   DecryptionKey *deckey = NULL;
   int pair_type_to_generate =
      (ischainroot) ? 
         KEY_GENERATE_TYPE_ROOT_ENCRYPT_DECRYPT :
         KEY_GENERATE_TYPE_LEAF_ENCRYPT_DECRYPT;
   if (policyoverridekeypair != AbstractKey::KEY_NULL_PAIR)
      pair_type_to_generate = policyoverridekeypair;
   int retval = generateNewEncryptionDecryptionKeys(pair_type_to_generate, name, &enckey, &deckey);
   if (retval == 0)
   {
      char *latest_by_owner_enc = NULL;
      char *latest_by_owner_dec = NULL;
      if ((ischained) && (!ischainroot))
      {
         // Latest keys in existence must be deprecated when required
         latest_by_owner_enc =
            encryptionkeys->getLatestKeyNameOfOwner(owner);
         latest_by_owner_dec =
            decryptionkeys->getLatestKeyNameOfOwner(owner);
      }
      // Make this whole thing atomic to prevent stuck key chains
      SQLiteAutoLock thislock(getAutoLock());
      if (latest_by_owner_enc)
      {
         Key t_latest_enc_chain(this, latest_by_owner_enc, Key::KEYPURPOSE_ENCRYPTION);
         t_latest_enc_chain.addKeyMark((char)KEYMARK_CHAIN, 1);
         t_latest_enc_chain.removeKeyMark((char)KEYMARK_CHAINLATEST);
         t_latest_enc_chain.commit();
      }
      if (latest_by_owner_dec)
      {
         Key t_latest_dec_chain(this, latest_by_owner_dec, Key::KEYPURPOSE_DECRYPTION);
         t_latest_dec_chain.addKeyMark((char)KEYMARK_CHAIN, 1);
         t_latest_dec_chain.removeKeyMark((char)KEYMARK_CHAINLATEST);
         t_latest_dec_chain.commit();
      }
      Key t_new_enc_chain(this, *enckey, oWIPpwd);
      t_new_enc_chain.addKeyMark((char)((isexpendable) ? (KEYMARK_EXPENDABLE) : (KEYMARK_PERMANENT)), 1);
      if (ischainroot) t_new_enc_chain.addKeyMark((char)KEYMARK_CHAINROOT, 1);
      if (ischained) t_new_enc_chain.addKeyMark((char)KEYMARK_CHAINLATEST, 1);
      t_new_enc_chain.setOwner(owner);
      t_new_enc_chain.setDateCreatedToNow();
      t_new_enc_chain.commit();
      Key t_new_dec_chain(this, *deckey, oWIPpwd);
      t_new_dec_chain.addKeyMark((char)((isexpendable) ? (KEYMARK_EXPENDABLE) : (KEYMARK_PERMANENT)), 1);
      if (ischainroot) t_new_dec_chain.addKeyMark((char)KEYMARK_CHAINROOT, 1);
      if (ischained) t_new_dec_chain.addKeyMark((char)KEYMARK_CHAINLATEST, 1);
      t_new_dec_chain.setOwner(owner);
      t_new_dec_chain.setDateCreatedToNow();
      t_new_dec_chain.commit();
      if (latest_by_owner_enc) free(latest_by_owner_enc);
      if (latest_by_owner_dec) free(latest_by_owner_dec);
      return 0;
   } else
   {
      errprint("problem generating encryption/decryption keys");
      return -1;
   }
}

/** Generate a key pair for signing and checking the signatures on
 * data and place it into the database with a given name.
 * 
 * @param ischained A boolean flag that states whether these keys are
 * to be inserted as part of a key chain. A key chain is a set of keys
 * owned by an actor, which begins with a root key. Keys are added
 * through time and removed when their reference count reaches zero.
 * 
 * @param isexpendable A boolean flag that states whether these keys
 * are expendable. If so, the key will be slowly moved into
 * obsolescence.
 * 
 * @param isforssh Whether the generated key pair is to be used for
 * SSH.
 * 
 * @param name The name for the key.
 * 
 * @param owner The actor that will own the key. Having this key to
 * encrypt or sign data proves that the actor in question is
 * legitimately working on behalf of the key owner. NULL signifies
 * that the name of the owner is the same as the name of the key.
 *
 * @param policyoverridekeypair Allows the specification of a keypair
 * type that is not specified in the key generation policy.
 * 
 * @return Returns zero when the keys were successfully generated and
 * added to their respective tables. This will return non-zero on an
 * error. */
int KeyDB::generateSgnChkPairIntoDB(int ischained, int isexpendable, int isforssh,
   const char *name, const char *owner, AbstractKey::keypairtype policyoverridekeypair)
{
   // Chained means limited expendability
   int numberofancestors = signingkeys->countKeyChainOfOwner(owner) +
                           checkingkeys->countKeyChainOfOwner(owner);
   int ischainroot = (numberofancestors == 0) && ischained;
   SigningKey *sgnkey = NULL;
   CheckingKey *chkkey = NULL;
   int pair_type_to_generate =
      (ischainroot) ? 
         KEY_GENERATE_TYPE_ROOT_CHECKING_SIGNING :
         KEY_GENERATE_TYPE_LEAF_CHECKING_SIGNING;
   if (isforssh)
      pair_type_to_generate =
         (ischainroot) ? 
            KEY_GENERATE_TYPE_ROOT_SSH_CHECKING_SIGNING :
            KEY_GENERATE_TYPE_LEAF_SSH_CHECKING_SIGNING;
   if (policyoverridekeypair != AbstractKey::KEY_NULL_PAIR)
      pair_type_to_generate = policyoverridekeypair;
   int retval = generateNewSigningCheckingKeys(pair_type_to_generate, name, &sgnkey, &chkkey);
   if (retval == 0)
   {
      char *latest_by_owner_sgn = NULL;
      char *latest_by_owner_chk = NULL;
      if ((ischained) && (!ischainroot))
      {
         // Latest keys in existence must be deprecated when required
         latest_by_owner_sgn =
            signingkeys->getLatestKeyNameOfOwner(owner);
         latest_by_owner_chk =
            checkingkeys->getLatestKeyNameOfOwner(owner);
      }
      // Make this whole thing atomic to prevent stuck key chains
      SQLiteAutoLock thislock(getAutoLock());
      if (latest_by_owner_sgn)
      {
         Key t_latest_sgn_chain(this, latest_by_owner_sgn, Key::KEYPURPOSE_SIGNING);
         t_latest_sgn_chain.addKeyMark((char)KEYMARK_CHAIN, 1);
         t_latest_sgn_chain.removeKeyMark((char)KEYMARK_CHAINLATEST);
         t_latest_sgn_chain.commit();
      }
      if (latest_by_owner_chk)
      {
         Key t_latest_chk_chain(this, latest_by_owner_chk, Key::KEYPURPOSE_CHECKING);
         t_latest_chk_chain.addKeyMark((char)KEYMARK_CHAIN, 1);
         t_latest_chk_chain.removeKeyMark((char)KEYMARK_CHAINLATEST);
         t_latest_chk_chain.commit();
      }
      Key t_new_sgn_chain(this, *sgnkey, oWIPpwd);
      t_new_sgn_chain.addKeyMark((char)((isexpendable) ? (KEYMARK_EXPENDABLE) : (KEYMARK_PERMANENT)), 1);
      if (ischainroot) t_new_sgn_chain.addKeyMark((char)KEYMARK_CHAINROOT, 1);
      if (ischained) t_new_sgn_chain.addKeyMark((char)KEYMARK_CHAINLATEST, 1);
      t_new_sgn_chain.setOwner(owner);
      t_new_sgn_chain.setDateCreatedToNow();
      t_new_sgn_chain.commit();
      Key t_new_chk_chain(this, *chkkey, oWIPpwd);
      t_new_chk_chain.addKeyMark((char)((isexpendable) ? (KEYMARK_EXPENDABLE) : (KEYMARK_PERMANENT)), 1);
      if (ischainroot) t_new_chk_chain.addKeyMark((char)KEYMARK_CHAINROOT, 1);
      if (ischained) t_new_chk_chain.addKeyMark((char)KEYMARK_CHAINLATEST, 1);
      t_new_chk_chain.setOwner(owner);
      t_new_chk_chain.setDateCreatedToNow();
      t_new_chk_chain.commit();
      if (latest_by_owner_sgn) free(latest_by_owner_sgn);
      if (latest_by_owner_chk) free(latest_by_owner_chk);
      return 0;
   } else
   {
      errprint("problem generating signing/checking keys");
      return -1;
   }
}

/** Creates the key tables if they do not already exist.
 * 
 * @return Returns a string list of constant strings which are the
 * names of the database tables. The list, but not the list items,
 * must be deleted by the caller. */
std::vector<const char *> *KeyDB::getTableNamesFromCreateTablesIfNecessary()
{
   static const char keytabledefinition[] =
      "(keyname char(64) primary key not null, "
       "keytype char(32), "
       "keydata char(4096), "
       "owner char(64), "
       "keymark char(16), "
       "usedrefcount decimal(10,0), "
       "existsrefcount decimal(10,0), "
       "rfc822date char(32))";
   std::vector<const char *> *keytables = new std::vector<const char *>();
   keytables->push_back(Key::keypurposetypename[0]);
   keytables->push_back(Key::keypurposetypename[1]);
   keytables->push_back(Key::keypurposetypename[2]);
   keytables->push_back(Key::keypurposetypename[3]);
   keytables->push_back(NULL);
   ensureTablesAreCreated(4,
      keytables->at(0), keytabledefinition,
      keytables->at(1), keytabledefinition,
      keytables->at(2), keytabledefinition,
      keytables->at(3), keytabledefinition);
   return keytables;
}

/** Generate a key pair for encryption and decryption with a given
 * name.
 * 
 * @param generatefunc A flag determining what type of key pair to
 * generate.
 * 
 * @param name The name for the key.
 * 
 * @param[out] enckey A pointer to the place to put the pointer to the
 * EncryptionKey object.
 * 
 * @param[out] deckey A pointer to the place to put the pointer to the
 * DecryptionKey object.
 * 
 * @return Returns zero when the keys were successfully generated and
 * added to their respective tables. This will return non-zero on an
 * error. */
int KeyDB::generateNewEncryptionDecryptionKeys(int generatefunc, const char *name, EncryptionKey **enckey, DecryptionKey **deckey)
{
   int t_generatefunc = generatefunc;
   switch (t_generatefunc)
   {
      case AbstractKey::KEY_ASYMMETRIC_PAIR_RSA:
      {
         RSAKeyPairGenerator *nrsakp = new RSAKeyPairGenerator(RSA_BITS, name);
         *enckey = (EncryptionKey *)(nrsakp->popPublicKey());
         *deckey = (DecryptionKey *)(nrsakp->popPrivateKey());
         // RSA key pair does not delete
         delete nrsakp;
         break;
      }
      case AbstractKey::KEY_SYMMETRIC_AES:
      {
         AESSymmetricKey *naessym = new AESSymmetricKey(AES_BITS, name);
         AESSymmetricKey *naessym_copy = new AESSymmetricKey(*naessym);
         *enckey = (EncryptionKey *)(naessym);
         *deckey = (DecryptionKey *)(naessym_copy);
         break;
      }
      default:
      {
         *enckey = NULL;
         *deckey = NULL;
         break;
      }
   }
   if ((*enckey == NULL) || (*deckey == NULL))
   {
      if (*enckey) delete *enckey;
      if (*deckey) delete *deckey;
      return -1;
   }
   (*enckey)->setKeyName(name);
   (*deckey)->setKeyName(name);
   return 0;
}

/** Generate a key pair with a given name for signing and checking
 * signatures on data.
 * 
 * @param generatefunc A flag determining what type of key pair to
 * generate.
 * 
 * @param name The name for the key.
 * 
 * @param[out] sgnkey A pointer to the place to put the pointer to the
 * SigningKey object.
 * 
 * @param[out] chkkey A pointer to the place to put the pointer to the
 * CheckingKey object.
 * 
 * @return Returns zero when the keys were successfully generated and
 * added to their respective tables. This will return non-zero on an
 * error. */
int KeyDB::generateNewSigningCheckingKeys(int generatefunc, const char *name, SigningKey **sgnkey, CheckingKey **chkkey)
{
   int t_generatefunc = generatefunc;
   switch (t_generatefunc)
   {
      case AbstractKey::KEY_ASYMMETRIC_PAIR_RSA:
      {
         RSAKeyPairGenerator *nrsakp = new RSAKeyPairGenerator(RSA_BITS, name);
         *chkkey = (CheckingKey *)(nrsakp->popPublicKey());
         *sgnkey = (SigningKey *)(nrsakp->popPrivateKey());
         // RSA key pair does not delete
         delete nrsakp;
         break;
      }
      case AbstractKey::KEY_ASYMMETRIC_PAIR_DSA:
      {
         DSAKeyPairGenerator *ndsakp = new DSAKeyPairGenerator(DSA_BITS, name);
         *chkkey = (CheckingKey *)(ndsakp->popPublicKey());
         *sgnkey = (SigningKey *)(ndsakp->popPrivateKey());
         // DSA key pair does not delete
         delete ndsakp;
         break;
      }
      case AbstractKey::KEY_ASYMMETRIC_PAIR_ECDSA:
      {
         ECDSAKeyPairGenerator *necdsakp = new ECDSAKeyPairGenerator(ECDSA_BITS, name);
         *chkkey = (CheckingKey *)(necdsakp->popPublicKey());
         *sgnkey = (SigningKey *)(necdsakp->popPrivateKey());
         // ECDSA key pair does not delete
         delete necdsakp;
         break;
      }
      default:
      {
         *chkkey = NULL;
         *sgnkey = NULL;
         break;
      }
   }
   if ((*chkkey == NULL) || (*sgnkey == NULL))
   {
      if (*chkkey) delete *chkkey;
      if (*sgnkey) delete *sgnkey;
      return -1;
   }
   (*chkkey)->setKeyName(name);
   (*sgnkey)->setKeyName(name);
   return 0;
}

/** Generate an encryption process object from a set of key names.
 * Each step is separate, so they can be composed by setting the given
 * variables appropriately.
 * 
 * @param enckeyname The name of an encryption key. NULL denotes no
 * key is used for this step.
 * 
 * @param sgnkeyname The name of a signing key. NULL denotes no key is
 * used for this step.
 * 
 * @param docompress Whether a compression step is to be done on the
 * data.
 * 
 * @return An encrypter process embodying these processes. */
EncryptWrapper *KeyDB::getEncrypter(const char *enckeyname, const char *sgnkeyname, bool docompress) const
{
   // Too troublesome to use special read-only versions of
   // SQLiteTransactor, const_cast it.
   EncryptionKey *enckey = ((enckeyname) && (strlen(enckeyname) > 0)) ? 
      Key::getEncryptionKey(const_cast<KeyDB *>(this), oWIPpwd, enckeyname) :
      NULL;
   SigningKey *sgnkey = ((sgnkeyname) && (strlen(sgnkeyname) > 0)) ?
      Key::getSigningKey(const_cast<KeyDB *>(this), oWIPpwd, sgnkeyname) :
      NULL;
   EncryptWrapper *temp_enc = new EncryptWrapper(enckey, sgnkey, docompress);
   delete enckey;
   delete sgnkey;
   return temp_enc;
}

/** Generate an decryption process object from a set of key names.
 * Each step is separate, so they can be composed by setting the given
 * variables appropriately.
 * 
 * @param deckeyname The name of an decryption key. NULL denotes no
 * key is used for this step.
 * 
 * @param chkkeyname The name of a checking key. NULL denotes no key
 * is used for this step.
 * 
 * @param dodecompress Whether a decompression step is to be attempted
 * on the data.
 * 
 * @return An decrypter process embodying these processes. */
DecryptWrapper *KeyDB::getDecrypter(const char *deckeyname, const char *chkkeyname, bool dodecompress) const
{
   // Too troublesome to use special read-only versions of
   // SQLiteTransactor, const_cast it.
   DecryptionKey *deckey = ((deckeyname) && (strlen(deckeyname) > 0)) ?
      Key::getDecryptionKey(const_cast<KeyDB *>(this), oWIPpwd, deckeyname) :
      NULL;
   CheckingKey *chkkey = ((chkkeyname) && (strlen(chkkeyname) > 0)) ? 
      Key::getCheckingKey(const_cast<KeyDB *>(this), oWIPpwd, chkkeyname) :
      NULL;
   DecryptWrapper *temp_dec = new DecryptWrapper(deckey, chkkey, dodecompress);
   delete deckey;
   delete chkkey;
   return temp_dec;
}

/** Delete all keys with the given name.
 * 
 * @param keyname The name of the keys to delete. */
void KeyDB::deleteAllKeys(const char *keyname) const
{
   if (keyname == NULL) return;
   encryptionkeys->deleteKey(keyname);
   decryptionkeys->deleteKey(keyname);
   signingkeys->deleteKey(keyname);
   checkingkeys->deleteKey(keyname);
}

/** Update to latest own keys. This can increase security but is
 * dangerous, as the wrong password can disrupt the keys and break the
 * session.
 * 
 * @param ownpwd The password to the keys of the owner of the
 * database. */
void KeyDB::updateOwnerKeysToLatest(const char *ownpwd)
{
   encryptionkeys->updateToLatestOwnKey(ownpwd);
   decryptionkeys->updateToLatestOwnKey(ownpwd);
   signingkeys->updateToLatestOwnKey(ownpwd);
   checkingkeys->updateToLatestOwnKey(ownpwd);
}

/** Get keys from external files and add them to the client database.
 * 
 * @param keydb_filename The filename for loading the key database.
 * 
 * @param keydb_WIPpwd The Work-In-Progress password for the key
 * database.
 * 
 * @param file_keys_list The list of files containing keys.
 * 
 * @param mp The memory pool to use.
 * 
 * @return Zero if all the key updates succeeded. */
int KeyDB::performExternalKeyUpdates(const char *keydb_filename, const char *keydb_WIPpwd,
   const char **file_keys_list, apr_pool_t *mp)
{
   KeyDB *kdb = new KeyDB(keydb_filename, keydb_WIPpwd, NULL, NULL, 1);
   int count = 0;
   int success = 0;
   while (file_keys_list[count] != NULL)
   {
      KeyTableView *ktable = NULL;
      if (strstr(file_keys_list[count], ".enc") != NULL) ktable = kdb->encryptionkeys;
      if (strstr(file_keys_list[count], ".dec") != NULL) ktable = kdb->decryptionkeys;
      if (strstr(file_keys_list[count], ".sgn") != NULL) ktable = kdb->signingkeys;
      if (strstr(file_keys_list[count], ".chk") != NULL) ktable = kdb->checkingkeys;
      int interm_success = ktable->updateKeyChainUsingFile(APRFile::expandPath(file_keys_list[count], mp), keydb_WIPpwd, mp);
      if (interm_success)
         errprint("problem importing keyfile '%s'", file_keys_list[count]);
      success ^= interm_success;
      count++;
   }
   delete kdb;
   return success;
}
